home *** CD-ROM | disk | FTP | other *** search
- /* DMA.C
- *
- * DMA handling routines
- *
- * $Id: dma.c,v 1.3 1997/01/16 18:41:59 pekangas Exp $
- *
- * Copyright 1996,1997 Housemarque Inc.
- *
- * This file is part of the MIDAS Sound System, and may only be
- * used, modified and distributed under the terms of the MIDAS
- * Sound System license, LICENSE.TXT. By continuing to use,
- * modify or distribute this file you indicate that you have
- * read the license and understand and accept it fully.
- */
-
- #include "lang.h"
- #include "mtypes.h"
- #include "errors.h"
- #include "mmem.h"
- #include "dma.h"
-
- #ifdef __DPMI__
- #include "dpmi.h"
- #endif
-
- RCSID(const char *dma_rcsid = "$Id: dma.c,v 1.3 1997/01/16 18:41:59 pekangas Exp $";)
-
-
-
- /****************************************************************************\
- * DMA channel data:
- \****************************************************************************/
-
- dmaChannel dmaChannels[8] = {
- { 0, 1, 0x00, 0x01, 0x09, 0x0A, 0x0B, 0x0C, 0x87 },
- { 1, 2, 0x02, 0x03, 0x09, 0x0A, 0x0B, 0x0C, 0x83 },
- { 2, 4, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x81 },
- { 3, 8, 0x06, 0x07, 0x09, 0x0A, 0x0B, 0x0C, 0x82 },
- { 4, 1, 0xC0, 0xC2, 0xD2, 0xD4, 0xD6, 0xD8, 0x8F },
- { 5, 2, 0xC4, 0xC6, 0xD2, 0xD4, 0xD6, 0xD8, 0x8B },
- { 6, 4, 0xC8, 0xCA, 0xD2, 0xD4, 0xD6, 0xD8, 0x89 },
- { 7, 8, 0xCC, 0xCE, 0xD2, 0xD4, 0xD6, 0xD8, 0x8A } };
-
-
-
- /* *!!* */
- #ifdef __WATCOMC__
-
- #ifdef __16__
-
- void outp(unsigned port, unsigned value);
- #pragma aux outp = \
- "out dx,al" \
- parm [dx] [ax] \
- modify exact [];
-
- unsigned inp(unsigned port);
- #pragma aux inp = \
- "xor ax,ax" \
- "in al,dx" \
- parm [dx] \
- value [ax] \
- modify exact [ax];
-
- #else
-
- void outp(unsigned port, unsigned value);
- #pragma aux outp = \
- "out dx,al" \
- parm [edx] [eax] \
- modify exact [];
-
- unsigned inp(unsigned port);
- #pragma aux inp = \
- "xor eax,eax" \
- "in al,dx" \
- parm [edx] \
- value [eax] \
- modify exact [eax];
-
- #endif
-
- #endif
-
- #ifdef __BORLANDC__
-
- void outp(unsigned port, unsigned value)
- {
- asm mov dx,word ptr port
- asm mov al,byte ptr value
- asm out dx,al
- }
-
- unsigned inp(unsigned port)
- {
- asm xor ax,ax
- asm in al,dx
- return _AX;
- }
-
- #endif
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dmaAllocBuffer(unsigned size, dmaBuffer *buf);
- *
- * Description: Allocates a DMA buffer (totally inside a 64K physical page)
- *
- * Input: unsigned size size of buffer in bytes
- * dmaBuffer *buf pointer to DMA buffer information
- *
- * Returns: MIDAS error code. DMA buffer information is written to *buf.
- *
- \****************************************************************************/
-
- int CALLING dmaAllocBuffer(unsigned size, dmaBuffer *buf)
- {
- int error;
- #ifdef __REALMODE__
- unsigned bseg;
- #endif
- #ifdef __DPMI__
- static ulong addr;
- #endif
-
- /* Check that buffer size is below 30000 bytes: */
- if ( size > 30000 )
- {
- ERROR(errInvalidArguments, ID_dmaAllocBuffer);
- return errInvalidArguments;
- }
-
- #ifdef __REALMODE__
- /* Allocate memory for 2*size bytes, to ensure the block always fits
- in a 64k physical page: */
- if ( (error = memAlloc(2 * size + 16, &buf->memBlk)) != OK )
- PASSERROR (ID_dmaAllocBuffer)
-
- /* bseg = allocated memory block segment: */
- bseg = *((unsigned*) ((uchar*)&buf->memBlk + 2)) +
- (((*(unsigned*) &buf->memBlk) + 15) >> 4);
- /* /me really hates 16-bit compilers */
-
- /* Move buffer to the beginning of the next 64k page if it does not fit
- into current one: */
- if ( (bseg & 0x0FFF) >= (0x0FFF - (size + 15) / 16) )
- bseg = (bseg & 0xF000) + 0x1000;
-
- buf->bufferSeg = bseg; /* buffer segment */
- buf->startAddr = ((ulong) bseg) << 4; /* buffer phys. start address */
-
- /* Create pointer to buffer data: */
- buf->dataPtr = (void*) (((ulong) bseg) << 16);
- #else
-
- /* Protected mode under DPMI: */
-
- /* This code assumes in the first megabyte the logical addresses
- correspond to the physical ones (mapped directly). */
-
- /* Allocate DOS memory for DMA buffer: */
- if ( (error = dpmiAllocDOSMem((2 * size + 32 + 1024) / 16, &buf->dosSeg,
- &buf->dpmiSel)) != OK )
- PASSERROR(ID_dmaAllocBuffer);
-
- /* Get the allocated memory block linear start address: */
- if ( (error = dpmiGetSegmentBase(buf->dpmiSel, &addr)) != OK )
- PASSERROR(ID_dmaAllocBuffer);
-
- /* Align to paragraph boundary: */
- // addr = (addr + 15) & 0xFFFFFFF0;
-
- /* Align to 512-byte boundary: */
- addr = (addr + 511) & (~511);
-
- /* Move the buffer in to the beginning of the next 64kb page if it does
- not fit into the current one: */
- if ( (addr & 0xFFFF) >= (0x10000 - size) )
- addr = (addr & 0xFFFF0000) + 0x10000;
-
- buf->startAddr = addr;
-
- /* Lock the DMA buffer memory area: */
- if ( (error = dpmiLockMemory(addr, size)) != OK )
- PASSERROR(ID_dmaAllocBuffer);
-
- #ifdef __FLATMODE__
- /* Build pointer to buffer data: */
- buf->dataPtr = (void*) buf->startAddr;
-
- #else
- /* Not fully flat memory - allocate descriptor for DMA buffer memory: */
- if ( (error = dpmiAllocDescriptor(&buf->bufferSeg)) != OK )
- PASSERROR(ID_dmaAllocBuffer)
-
- /* Set new segment base and limit to the DMA buffer: */
- if ( (error = dpmiSetSegmentBase(buf->bufferSeg, addr)) != OK )
- PASSERROR(ID_dmaAllocBuffer)
- if ( (error = dpmiSetSegmentLimit(buf->bufferSeg, size)) != OK )
- PASSERROR(ID_dmaAllocBuffer)
-
- #ifdef __16__
- /* Build pointer to buffer data: */
- buf->dataPtr = (void*) (((ulong) buf->bufferSeg) << 16);
- #else
- /* Build pointer to buffer data: */
- *((ushort*)(((ulong) &buf->dataPtr) + 4) = buf->bufferSeg; /* segment */
- *((ulong*)(((ulong) &buf->dataPtr)) = 0; /* offset */
- #endif
-
- #endif
- #endif
-
- buf->bufferLen = size;
- buf->channel = -1;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dmaFreeBuffer(dmaBuffer *buf);
- *
- * Description: Deallocates an allocated DMA buffer
- *
- * Input: dmaBuffer *buf pointer to DMA buffer information
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dmaFreeBuffer(dmaBuffer *buf)
- {
- int error;
- #ifdef __REALMODE__
- /* Deallocate buffer memory block: */
- if ( (error = memFree(buf->memBlk)) != OK )
- PASSERROR(ID_dmaFreeBuffer)
- #else
- /* Unlock the DMA buffer memory area: */
- if ( (error = dpmiLockMemory(buf->startAddr, buf->bufferLen)) != OK )
- PASSERROR(ID_dmaFreeBuffer);
-
- /* Deallocate DOS memory: */
- if ( (error = dpmiFreeDOSMem(buf->dpmiSel)) != OK )
- PASSERROR(ID_dmaFreeBuffer)
-
- #ifndef __FLATMODE__
- /* Deallocate DPMI selector: */
- if ( (error = dpmiFreeSelector(buf->bufferSeg)) != OK )
- PASSERROR(ID_dmaFreeBuffer)
- #endif
- #endif
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dmaPlayBuffer(dmaBuffer *buf, unsigned channel,
- * unsigned autoInit);
- *
- * Description: Plays a DMA buffer
- *
- * Input: dmaBuffer *buf pointer to DMA buffer information
- * unsigned channel DMA channel number
- * unsigned autoInit 1 if autoinitializing DMA is used, 0
- * if not
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dmaPlayBuffer(dmaBuffer *buf, unsigned channel, unsigned autoInit)
- {
- dmaChannel *chan;
-
- /* Point chan to correct DMA channel information structure: */
- chan = &dmaChannels[channel];
-
- buf->channel = channel;
-
- /* Reset DMA request: */
- outp(chan->request, channel & 3);
-
- /* Mask out the channel: */
- outp(chan->singleMask, (channel & 3) | 4);
-
- if ( autoInit )
- {
- /* Read mode, single mode, autoinitialization: */
- outp(chan->mode, (channel & 3) | 8 | 16 | 64);
- }
- else
- {
- /* Read mode, single mode, no autoinitialization: */
- outp(chan->mode, (channel & 3) | 8 | 64);
- }
-
- /* Set DMA page: */
- outp(chan->page, (buf->startAddr >> 16L));
-
- /* Clear byte pointer flip-flop so that next write to a 16-bit register
- will go to the low byte: */
- outp(chan->clearFF, 0);
-
- /* Set DMA start address and buffer length: */
- if ( channel < 4 )
- {
- /* 8-bit DMA channel - just set the address: */
- outp(chan->baseAddr, (buf->startAddr & 0xFF));
- outp(chan->baseAddr, (buf->startAddr & 0xFFFF) >> 8);
-
- /* Set word count: */
- outp(chan->wordCount, (buf->bufferLen-1) & 0xFF);
- outp(chan->wordCount, ((buf->bufferLen-1) & 0xFFFF) >> 8);
- }
- else
- {
- /* 16-bit DMA channel - divide address by 2 (starting word) */
- outp(chan->baseAddr, (buf->startAddr >> 1) & 0xFF);
- outp(chan->baseAddr, ((buf->startAddr >> 1) & 0xFFFF) >> 8);
-
- /* Set word count: */
- outp(chan->wordCount, ((buf->bufferLen >> 1)-1) & 0xFF);
- outp(chan->wordCount, (((buf->bufferLen >> 1)-1) & 0xFFFF) >> 8);
- }
-
- /* Enable channel: */
- outp(chan->singleMask, channel & 3);
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dmaStop(unsigned channel);
- *
- * Description: Stops DMA playing
- *
- * Input: unsigned channel DMA channel number
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dmaStop(unsigned channel)
- {
- dmaChannel *chan;
-
- /* Point chan to correct DMA channel info structure: */
- chan = &dmaChannels[channel];
-
- /* Mask out channel: */
- outp(chan->singleMask, (channel & 3) | 4);
-
- /* Clear byte pointer flip-flop: */
- outp(chan->clearFF, 0);
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dmaGetPos(dmaBuffer *buf, unsigned *pos);
- *
- * Description: Reads the DMA playing position
- *
- * Input: dmaBuffer *buf pointer to DMA buffer information
- * unsigned *pos pointer to playing position
- *
- * Returns: MIDAS error code. DMA playing position from the beginning
- * of the buffer, in bytes, is written to *pos.
- *
- \****************************************************************************/
-
- int CALLING dmaGetPos(dmaBuffer *buf, unsigned *pos)
- {
- dmaChannel *chan;
- int count1, count2;
-
- /* Point chan to correct DMA channel info structure: */
- chan = &dmaChannels[buf->channel];
-
- /* Clear byte pointer flip-flop: */
- outp(chan->clearFF, 0);
-
- /* Read DMA word count two times until the difference between the
- counts read is below or equal to 4 and the value is legal:
- (make sure we won't be disturbed by Expanded Memory Managers or
- something) */
- do
- {
- count1 = inp(chan->wordCount);
- count1 = count1 + ((inp(chan->wordCount)) << 8);
-
- /* Convert count1 to number of bytes if the channel is 16-bit: */
- if ( buf->channel > 3 )
- count1 = count1 << 1;
-
- count2 = inp(chan->wordCount);
- count2 = count2 + ((inp(chan->wordCount)) << 8);
-
- /* Convert count2 to number of bytes if the channel is 16-bit: */
- if ( buf->channel > 3 )
- count2 = count2 << 1;
- } while ( ((count1 - count2) > 4) || ((count1 - count2) < (-4)) ||
- (count1 >= buf->bufferLen) );
-
- /* Write position to *pos: */
- *pos = buf->bufferLen - count1;
-
- return OK;
- }
-
-
- /*
- * $Log: dma.c,v $
- * Revision 1.3 1997/01/16 18:41:59 pekangas
- * Changed copyright messages to Housemarque
- *
- * Revision 1.2 1996/10/13 17:06:54 pekangas
- * Now properly masks out channel in dmaStop()
- *
- * Revision 1.1 1996/05/22 20:49:33 pekangas
- * Initial revision
- *
- */